<template>
	<view class="rich-content" @tap="handleTap">
		<rich-text
			:nodes="parsedNodes"
			:style="computedStyle"
			class="rich-text-wrapper"
		/>
	</view>
</template>

<script>
import marked from 'marked';

// ========================
// 1. 自定义 marked 渲染器（避免生成不支持的标签）
// ========================
const renderer = new marked.Renderer();

// 标题：转为 <p><strong># 标题</strong></p>
renderer.heading = (text, level) => {
	const prefix = '#'.repeat(level) + ' ';
	return `<p><strong>${prefix}${text}</strong></p>`;
};

// 分割线
renderer.hr = () => {
	return `<p>──────────────</p>`;
};

// 引用块：每行加 > 前缀
renderer.blockquote = text => {
	// 处理内部可能含 <p> 的情况
	let cleanText = text
		.replace(/<p>/g, '')
		.replace(/<\/p>/g, '\n')
		.replace(/\n+/g, '\n')
		.trim();
	const lines = cleanText.split('\n').filter(l => l.trim());
	const quoted = lines.map(line => `&gt; ${line}`).join('<br>');
	return `<p>${quoted}</p>`;
};

// 行内代码
renderer.codespan = code => {
	return `\`${code}\``;
};

// 代码块
renderer.code = (code, language) => {
	const lang = language ? `[${language}]` : '';
	const lines = code.split('\n').filter(l => l.trim() !== '');
	const indented = lines.map(line => `  ${line}`).join('<br>');
	return `<p>${lang ? lang + '<br>' : ''}${indented}</p>`;
};

// 图片：添加 data-src 用于预览
renderer.image = (href, title, text) => {
	// 转义引号防止 XSS
	const src = href.replace(/"/g, '&quot;');
	const alt = (text || '').replace(/"/g, '&quot;');
	const t = (title || '').replace(/"/g, '&quot;');
	return `<img src="${src}" data-src="${src}" alt="${alt}" title="${t}">`;
};

// 链接：添加 data-href
renderer.link = (href, title, text) => {
	const url = href.replace(/"/g, '&quot;');
	const txt = text.replace(/"/g, '&quot;');
	const t = (title || '').replace(/"/g, '&quot;');
	return `<a href="${url}" data-href="${url}" title="${t}">${txt}</a>`;
};

// 配置 marked
marked.setOptions({
	renderer,
	gfm: true,
	breaks: true,
	smartLists: true,
	smartypants: false,
});

// ========================
// 2. 工具函数：转换不支持的 HTML 标签（用于传入 HTML 时）
// ========================
function convertUnsupportedHtmlTags(html) {
	if (!html) return html;

	// h1-h6 → # 标题（加粗段落）
	html = html.replace(
		/<h([1-6])\b[^>]*>(.*?)<\/h\1>/gi,
		(match, level, content) => {
			return `<p><strong>${'#'.repeat(level)} ${content}</strong></p>`;
		}
	);

	// hr → 分割线
	html = html.replace(/<hr\b[^>]*>/gi, '<p>──────────────</p>');

	// blockquote → > 前缀
	html = html.replace(
		/<blockquote\b[^>]*>((?:.|\n)*?)<\/blockquote>/gi,
		(match, inner) => {
			let text = inner
				.replace(/<[^>]+>/g, ' ') // 移除所有标签
				.replace(/\s+/g, ' ')
				.trim();
			if (!text) return '<p>&gt; </p>';
			const lines = text.split(/[\n\r]+/).filter(l => l.trim());
			const quoted = lines.map(line => `&gt; ${line.trim()}`).join('<br>');
			return `<p>${quoted}</p>`;
		}
	);

	// code → 反引号包裹
	html = html.replace(/<code\b[^>]*>((?:.|\n)*?)<\/code>/gi, (match, inner) => {
		let clean = inner.replace(/<[^>]+>/g, '');
		return `\`${clean}\``;
	});

	// pre → 缩进代码块
	html = html.replace(/<pre\b[^>]*>((?:.|\n)*?)<\/pre>/gi, (match, inner) => {
		let clean = inner.replace(/<[^>]+>/g, '');
		const lines = clean.split(/[\n\r]+/).filter(l => l.trim());
		const indented = lines.map(line => `  ${line.trim()}`).join('<br>');
		return `<p>${indented}</p>`;
	});

	// dl/dt/dd → 转为 p
	html = html.replace(/<dl\b[^>]*>((?:.|\n)*?)<\/dl>/gi, (match, inner) => {
		return inner
			.replace(/<dt\b[^>]*>/gi, '<p><strong>')
			.replace(/<\/dt>/gi, ':</strong></p>')
			.replace(/<dd\b[^>]*>/gi, '<p>　　') // 中文全角空格缩进
			.replace(/<\/dd>/gi, '</p>');
	});

	return html;
}

// ========================
// 3. 安全过滤函数
// ========================
function sanitizeHtml(html) {
	if (!html) return '';
	return html
		.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
		.replace(/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi, '')
		.replace(/<iframe\b[^<]*(?:(?!<\/iframe>)<[^<]*)*<\/iframe>/gi, '')
		.replace(/<object\b[^<]*(?:(?!<\/object>)<[^<]*)*<\/object>/gi, '')
		.replace(/<embed\b[^<]*(?:(?!<\/embed>)<[^<]*)*<\/embed>/gi, '')
		.replace(/javascript:/gi, 'javascript-disabled:');
}

// ========================
// 4. 组件定义
// ========================
export default {
	name: 'RichContent',
	props: {
		content: {
			type: String,
			default: '',
		},
		type: {
			type: String,
			default: 'auto', // 'html' | 'markdown' | 'auto'
			validator(value) {
				return ['html', 'markdown', 'auto'].includes(value);
			},
		},
		customStyle: {
			type: [String, Object],
			default: '',
		},
		previewImage: {
			type: Boolean,
			default: true,
		},
	},
	data() {
		return {
			parsedNodes: [],
		};
	},
	computed: {
		computedStyle() {
			if (typeof this.customStyle === 'string') {
				return this.customStyle;
			}
			return Object.entries(this.customStyle)
				.map(([k, v]) => `${k}: ${v}`)
				.join('; ');
		},
	},
	watch: {
		content: {
			handler() {
				this.parseContent();
			},
			immediate: true,
		},
		type: {
			handler() {
				this.parseContent();
			},
		},
	},
	methods: {
		isMarkdown(str) {
			if (!str || typeof str !== 'string') return false;
			const patterns = [
				/^#{1,6}\s/,
				/\*\*.*?\*\*/,
				/__.*?__/,
				/\*.*?\*/,
				/_.*?_/,
				/^[-*+]\s/,
				/^\d+\.\s/,
				/!$$.*?$$$.*?$/,
				/$$.*?$$$.*?$/,
			];
			return patterns.some(p => p.test(str));
		},

		parseContent() {
			let html = '';
			const { content, type } = this;

			if (!content) {
				this.parsedNodes = [];
				return;
			}

			if (type === 'markdown') {
				html = marked(content);
			} else if (type === 'html') {
				let safeHtml = sanitizeHtml(content);
				safeHtml = convertUnsupportedHtmlTags(safeHtml);
				html = safeHtml;
			} else if (type === 'auto') {
				if (this.isMarkdown(content)) {
					html = marked(content);
				} else {
					let safeHtml = sanitizeHtml(content);
					safeHtml = convertUnsupportedHtmlTags(safeHtml);
					html = safeHtml;
				}
			}

			// 最终安全过滤（双重保险）
			html = sanitizeHtml(html);

			// rich-text nodes 格式（使用 { html } 对象，兼容性较好）
			this.parsedNodes = [{ html }];
		},

		handleTap(e) {
			const target = e.target;
			if (!target) return;

			// 图片预览
			if (this.previewImage && target.dataset && target.dataset.src) {
				const src = target.dataset.src;
				if (src) {
					uni.previewImage({
						urls: [src],
						current: src,
					});
				}
				return;
			}

			// 链接跳转
			if (target.dataset && target.dataset.href) {
				const url = target.dataset.href;
				if (!url) return;

				// H5 直接跳转
				if (process.env.VUE_APP_PLATFORM === 'h5') {
					window.open(url, '_blank');
				} else {
					// 小程序/APP：跳转到 webview 页面（需自行创建）
					// 或使用 uni.openUrl（部分平台支持）
					uni
						.navigateTo({
							url: `/pages/webview/webview?url=${encodeURIComponent(url)}`,
						})
						.catch(() => {
							uni.showToast({ title: '不支持跳转', icon: 'none' });
						});
				}
			}
		},
	},
};
</script>

<style scoped>
.rich-content {
	width: 100%;
	overflow: hidden;
	box-sizing: border-box;
}
.rich-text-wrapper {
	width: 100%;
	display: block;
}
</style>
